package com.xiaoyu.lanling.feature.chat.controller

import `in`.srain.cube.concurrent.SimpleTask
import `in`.srain.cube.util.CLog
import `in`.srain.cube.util.LocalDisplay
import `in`.srain.cube.util.UTUtil
import `in`.srain.cube.util.general.GeneralUtil
import `in`.srain.cube.util.internal.AppConsumer
import `in`.srain.cube.views.list.CubeRecyclerViewSimpleAdapter
import android.Manifest
import android.annotation.SuppressLint
import android.app.ProgressDialog
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.text.SpannableString
import android.text.TextUtils
import android.text.style.RelativeSizeSpan
import android.view.MotionEvent
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.DecelerateInterpolator
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.SimpleItemAnimator
import androidx.viewpager.widget.ViewPager.SimpleOnPageChangeListener
import cn.dreamtobe.kpswitch.util.KPSwitchConflictUtil
import cn.dreamtobe.kpswitch.util.KeyboardUtil
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.postprocessors.IterativeBoxBlurPostProcessor
import com.github.florent37.viewanimator.ViewAnimator
import com.opensource.svgaplayer.SVGACallback
import com.opensource.svgaplayer.SVGADrawable
import com.tbruyelle.rxpermissions2.RxPermissions
import com.xiaoyu.base.app.AppContext
import com.xiaoyu.base.app.GlobalUI
import com.xiaoyu.base.data.UserData
import com.xiaoyu.base.model.User
import com.xiaoyu.base.utils.RxUtils
import com.xiaoyu.base.utils.extensions.dp
import com.xiaoyu.base.utils.extensions.getViewTag
import com.xiaoyu.base.utils.extensions.setOnClickDebounceListener
import com.xiaoyu.base.utils.extensions.setViewTag
import com.xiaoyu.im.provider.ConversationManager
import com.xiaoyu.im.util.ChatDraftUtils
import com.xiaoyu.lanling.R
import com.xiaoyu.lanling.common.Constant
import com.xiaoyu.lanling.data.SvgaData
import com.xiaoyu.lanling.feature.chat.activity.ChatActivity
import com.xiaoyu.lanling.feature.chat.adapter.ChatMessageAdapter
import com.xiaoyu.lanling.feature.chat.contract.ChatContract
import com.xiaoyu.lanling.feature.chat.fragment.ChatEmojiFragment
import com.xiaoyu.lanling.feature.chat.fragment.ChatIntimacyDialogFragment
import com.xiaoyu.lanling.feature.chat.model.intent.ChatIntentModel
import com.xiaoyu.lanling.feature.chat.model.message.ChatMessageBaseItem
import com.xiaoyu.lanling.feature.chat.model.message.ChatMessageSendBaseItem
import com.xiaoyu.lanling.feature.chat.model.relationship.Intimacy
import com.xiaoyu.lanling.feature.chat.model.relationship.Intimacy.Companion.MIN_TOTAL_NUM
import com.xiaoyu.lanling.feature.chat.model.tease.TeaseItem
import com.xiaoyu.lanling.feature.chat.presenter.ChatPresenter
import com.xiaoyu.lanling.feature.chat.viewholder.ChatViewHolderManager
import com.xiaoyu.lanling.feature.chat.viewholder.tease.TeaseViewHolder
import com.xiaoyu.lanling.feature.gift.ChatGiftBottomSheetDialog
import com.xiaoyu.lanling.feature.gift.data.GiftData
import com.xiaoyu.lanling.feature.gift.model.Gift
import com.xiaoyu.lanling.feature.videocall.data.VideoCallData
import com.xiaoyu.lanling.feature.voicecall.util.VoiceCallNotificationUtils
import com.xiaoyu.lanling.feature.voicematch.activity.VoiceMatchWaitingActivity
import com.xiaoyu.lanling.lifecycle.disposeOn
import com.xiaoyu.lanling.media.image.ImageLoadParam
import com.xiaoyu.lanling.media.image.ImageViewUtil
import com.xiaoyu.lanling.media.image.UserImageLoadParam
import com.xiaoyu.lanling.media.selector.MediaSelector
import com.xiaoyu.lanling.media.selector.MediaSelectorFromType
import com.xiaoyu.lanling.router.Router
import com.xiaoyu.lanling.util.TextViewUtil
import com.xiaoyu.lanling.view.FragmentAdapter
import com.xiaoyu.lanling.view.OnShowFragment
import com.xiaoyu.lanling.view.listener.BaseTextWatcher
import com.xiaoyu.lanling.widget.audio.AudioRecordViewFragment
import com.xiaoyu.lib_av.datamodel.CallParams
import com.xiaoyu.lib_av.manager.AgoraManager
import com.xiaoyu.net.util.NetUtils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.functions.Action
import kotlinx.android.synthetic.main.activity_chat.*
import kotlinx.android.synthetic.main.toolbar_chat.*
import kotlinx.android.synthetic.main.view_chat_emoji.*
import kotlinx.android.synthetic.main.view_chat_media_audio_record.*
import kotlinx.android.synthetic.main.view_chat_tease.*
import java.util.*
import kotlin.let

class ChatViewController(val activity: ChatActivity) : ChatContract.View {

    private var mProgressDialog: ProgressDialog? = null

    private val presenter = ChatPresenter(this)
    private val messageAdapter = ChatMessageAdapter()
    private val teaseAdapter = CubeRecyclerViewSimpleAdapter<TeaseItem>()
    private var mAudioRecordViewFragment: AudioRecordViewFragment? = null

    private val editTexWatcher = EditTextWatcher()

    private var mGiftAnimator: ViewAnimator? = null
    private var isGiftAnimationPlaying: Boolean = false
    private val mAnimationQueue: Queue<Gift> = LinkedList<Gift>()
    private var mChatIntentModel: ChatIntentModel? = null
    private val SHORT_VIDEO_MINIMUM_INTIMACY_LIMIT = 2

    private var mSvgaAnimationDisposable: Disposable? = null

    init {
        initView()
        initAdapter()
        initBind()
        presenter.initEvent(activity)
        initData()
    }

    private fun initView() {
        activity.background.layoutParams.width = LocalDisplay.SCREEN_WIDTH_PIXELS
        activity.background.layoutParams.height = LocalDisplay.SCREEN_HEIGHT_PIXELS
        KeyboardUtil.attach(activity, activity.chat_bottom_emoji_layout)
    }

    private fun initAdapter() {
        ChatViewHolderManager.bindViewHolder(messageAdapter)
        activity.message_recyclerview.adapter = messageAdapter

        activity.message_recyclerview.itemAnimator?.addDuration = 0
        activity.message_recyclerview.itemAnimator?.removeDuration = 0
        activity.message_recyclerview.itemAnimator?.changeDuration = 0
        activity.message_recyclerview.itemAnimator?.moveDuration = 0
        (activity.message_recyclerview.itemAnimator as? SimpleItemAnimator)?.supportsChangeAnimations = false

        teaseAdapter.setViewHolderClass(0, null, TeaseViewHolder::class.java, 9)
        activity.chat_media_tease_layout.adapter = teaseAdapter
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun initBind() {
        activity.toolbar_back.setOnClickDebounceListener {
            finish()
        }
        activity.toolbar_more.setOnClickDebounceListener {
            mChatIntentModel?.mUser?.let {
                Router.instance.gotoUserActivity(activity, it)
            }
        }
        activity.intimacy_layout.setOnClickDebounceListener {
            val intimacy = it.getViewTag<Intimacy>() ?: return@setOnClickDebounceListener
            mChatIntentModel?.mUser?.let { toUser ->
                ChatIntimacyDialogFragment.show(activity.supportFragmentManager, toUser, intimacy)
            }
        }
        activity.swipe_refresh_layout.setOnRefreshListener {
            presenter.loadMoreMessageList()
        }
        activity.message_recyclerview.setOnTouchListener { v, event ->
            if (event.action == MotionEvent.ACTION_UP) {
                hideMediaLayout()
            }
            return@setOnTouchListener false
        }
        activity.edit_text.setOnFocusChangeListener { _, hasFocus ->
            if (hasFocus) {
                scrollToBottom()
                activity.chat_bottom_emoji_layout.visibility = View.GONE
            }
        }

        activity.edit_text.setOnClickListener {
            activity.chat_bottom_emoji_layout.visibility = View.GONE
        }
        activity.send.setOnClickDebounceListener {
            if (activity.edit_text.length() > 0) {
                val text: String = activity.edit_text.text.toString()
                presenter.sendMessageText(text)
                activity.edit_text.setText("")
                scrollToBottom()
            }
        }
        activity.gift.setOnClickDebounceListener {
            showGiftDialog()
        }
        activity.call.setOnClickDebounceListener {
            checkPermissionForAudio(Runnable {
                if (VoiceMatchWaitingActivity.isShowing) {
                    GlobalUI.getInstance().showToast(R.string.call_is_calling_toast)
                    return@Runnable
                }
                if (AgoraManager.getInstance().isCalling) {
                    // TODO @sanshi join videoCall or voiceCall by channelId
                    // val uid = mChatIntentModel?.mChatToken?.uid
                    // if (AgoraManager.getInstance().isCalling(uid)) {
                    //     hideMediaLayout()
                    //     val intent = Intent(AppContext.getContext(), ChatCallActivity::class.java)
                    //     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
                    //     AppContext.getContext().startActivity(intent)
                    // } else {
                    GlobalUI.getInstance().showToast(R.string.call_is_calling_toast)
                    // }
                    return@Runnable
                }

                mChatIntentModel?.let { model ->
                    val params = Bundle()
                    params.putString("chat_id", model.mChatToken.chatId)
                    params.putString("target_uid", model.mUser?.uid)
                    if (mChatIntentModel?.isGroupChat == true) {
                        GlobalUI.getInstance().showToast("群聊语音不可用")
                        params.putString("feedback", "group_limit")
                        UTUtil.getInstance().logEvent("call_chat_click", params)
                        return@let
                    }
                    if (!NetUtils.isConnected(AppContext.getContext(), true)) {
                        params.putString("feedback", "other")
                        UTUtil.getInstance().logEvent("call_chat_click", params)
                        return@let
                    }
                    hideMediaLayout()

                    showCallActionMenu(model)
                }
            })
        }
        activity.edit_text.addTextChangedListener(editTexWatcher)
        activity.tease.setOnClickDebounceListener {
            presenter.loadTeaseList()

            if (activity.chat_bottom_emoji_layout.visibility != View.VISIBLE) {
                activity.chat_media_emoji_layout.visibility = View.GONE
                activity.chat_media_tease_layout.visibility = View.VISIBLE
                activity.chat_media_audio_record_layout.visibility = View.GONE
                KPSwitchConflictUtil.showPanel(activity.chat_bottom_emoji_layout)
            } else if (activity.chat_media_emoji_layout.visibility == View.VISIBLE || activity.chat_media_audio_record_layout.visibility == View.VISIBLE) {
                activity.chat_media_emoji_layout.visibility = View.GONE
                activity.chat_media_tease_layout.visibility = View.VISIBLE
                activity.chat_media_audio_record_layout.visibility = View.GONE
            } else {
                hideMediaLayout()
            }
        }
        activity.emoji.setOnClickDebounceListener {
            loadEmoji()

            if (activity.chat_bottom_emoji_layout.visibility != View.VISIBLE) {
                activity.chat_media_emoji_layout.visibility = View.VISIBLE
                activity.chat_media_tease_layout.visibility = View.GONE
                activity.chat_media_audio_record_layout.visibility = View.GONE
                KPSwitchConflictUtil.showPanel(activity.chat_bottom_emoji_layout)
            } else if (activity.chat_media_tease_layout.visibility == View.VISIBLE || activity.chat_media_audio_record_layout.visibility == View.VISIBLE) {
                activity.chat_media_emoji_layout.visibility = View.VISIBLE
                activity.chat_media_tease_layout.visibility = View.GONE
                activity.chat_media_audio_record_layout.visibility = View.GONE
            } else {
                hideMediaLayout()
            }
        }
        activity.audio.setOnClickDebounceListener {
            initAudioRecord()
            if (activity.chat_bottom_emoji_layout.visibility != View.VISIBLE) {
                activity.chat_media_emoji_layout.visibility = View.GONE
                activity.chat_media_tease_layout.visibility = View.GONE
                activity.chat_media_audio_record_layout.visibility = View.VISIBLE
                changeAudioRecordLifecycle(true)
                KPSwitchConflictUtil.showPanel(activity.chat_bottom_emoji_layout)
            } else if (activity.chat_media_emoji_layout.visibility == View.VISIBLE || activity.chat_media_tease_layout.visibility == View.VISIBLE) {
                activity.chat_media_emoji_layout.visibility = View.GONE
                activity.chat_media_tease_layout.visibility = View.GONE
                activity.chat_media_audio_record_layout.visibility = View.VISIBLE
                changeAudioRecordLifecycle(true)
            } else {
                hideMediaLayout()
            }
        }
        activity.album.setOnClickDebounceListener {
            checkPermissionForCamera(Action {
                val intimacy = (activity.camera.getViewTag<Intimacy>())?.totalNum ?: 0
                if (intimacy >= SHORT_VIDEO_MINIMUM_INTIMACY_LIMIT) {
                    MediaSelector.instance.selectorForTinyVideo(1, 16000, MediaSelectorFromType.CHAT, AppContext.getString(R.string.camera_video_longer_than_15s))
                } else {
                    MediaSelector.instance.selectorForImage(1, true, MediaSelectorFromType.CHAT)
                }
            })
        }
        activity.camera.setOnClickDebounceListener {
            val intimacy = (it.getViewTag<Intimacy>())?.totalNum ?: 0
            if (intimacy < SHORT_VIDEO_MINIMUM_INTIMACY_LIMIT) {
                GlobalUI.getInstance().showToast(R.string.chat_video_unlock_intimacy_hint)
                return@setOnClickDebounceListener
            }
            checkPermissionForCameraAndAudio(Action {
                Router.instance.gotoCameraActivity(activity)
                logForShortVideoEvent()
            })
        }
        activity.svga_animation_view.callback = object : SVGACallback {
            override fun onPause() {
                clearGiftAnimation()
            }

            override fun onFinished() {
                activity.svga_animation_view.visibility = View.GONE
                isGiftAnimationPlaying = false
                if (!mAnimationQueue.isEmpty()) {
                    playGiftAnimation(mAnimationQueue.poll())
                }
            }

            override fun onRepeat() {}
            override fun onStep(frame: Int, percentage: Double) {}
        }
    }

    private fun logForShortVideoEvent() {
        UTUtil.getInstance().flushEvent("short_video")
    }

    private fun showCallActionMenu(model: ChatIntentModel) {
        model.mUser?.let { user ->
            val videoPrefix = AppContext.getString(R.string.chat_call_action_menu_video)
            val videoSuffix = AppContext.getString(R.string.chat_call_action_menu_video_suffix)
            val videoSpannableString = SpannableString(videoPrefix + videoSuffix)
            videoSpannableString.setSpan(RelativeSizeSpan(0.75F), videoPrefix.length, videoSpannableString.length, SpannableString.SPAN_EXCLUSIVE_INCLUSIVE)

            val voicePrefix = AppContext.getString(R.string.chat_call_action_menu_voice)
            val voiceSuffix = AppContext.getString(R.string.chat_call_action_menu_voice_suffix)
            val voiceSpannableString = SpannableString(voicePrefix + voiceSuffix)
            voiceSpannableString.setSpan(RelativeSizeSpan(0.75F), voicePrefix.length, voiceSpannableString.length, SpannableString.SPAN_EXCLUSIVE_INCLUSIVE)

            val items = arrayOf(videoSpannableString, voiceSpannableString)
            AlertDialog.Builder(activity)
                    .setItems(items) { dialog: DialogInterface, which: Int ->
                        activity.call.isEnabled = false
                        when (which) {
                            0 -> VideoCallData.getCallParams(user.uid, AppConsumer {
                                activity.call.isEnabled = true
                                val params = CallParams.fromJson(it)
                                if (params.isInvalid) {
                                    return@AppConsumer
                                }
                                Router.instance.gotoVideoCallActivity(activity, params, model.mFromType, true)
                            })
                            1 -> {
                                activity.call.isEnabled = true
                                Router.instance.gotoChatCallActivity(activity, user.uid, model.mFromType, true)
                            }
                        }
                    }
                    .show()
        }
    }

    private fun loadEmoji() {
        if (activity.chat_emoji_view_pager.adapter != null) {
            return
        }

        val fragments = mutableListOf<OnShowFragment>()
        val titles = mutableListOf<CharSequence>()
        fragments.add(ChatEmojiFragment.newInstance())
        titles.add("emoji")

        val adapter = FragmentAdapter(activity.supportFragmentManager, fragments, titles)
        activity.chat_emoji_view_pager.adapter = adapter
        activity.chat_emoji_view_pager.setSmoothScroll(false)
        activity.chat_emoji_view_pager.offscreenPageLimit = 5
        activity.chat_emoji_view_pager.addOnPageChangeListener(object : SimpleOnPageChangeListener() {
            override fun onPageSelected(position: Int) {
                adapter.tryShowOnIndex(position)
            }
        })
    }

    private fun initData() {
        presenter.processIntent(activity.intent)
    }

    override fun onPause() {
        KeyboardUtil.hideKeyboard(activity.edit_text)
    }

    override fun onStop() {
        clearGiftAnimation()
        presenter.updateConversationViewVisible(false)
    }

    override fun onDestroy() {
        unbind()
        presenter.onStopChat()
    }

    private fun unbind() {
        activity.edit_text.removeTextChangedListener(editTexWatcher)
    }

    override fun finish() {
        activity.finish()
    }

    override fun onBackPressed(): Boolean {
        return if (activity.chat_bottom_emoji_layout.visibility == View.VISIBLE) {
            hideMediaLayout()
            true
        } else {
            false
        }
    }

    override fun onNewIntent(intent: Intent) {
        initData()
    }

    override fun setChatModel(chatIntentModel: ChatIntentModel) {
        mChatIntentModel = chatIntentModel

        chatIntentModel.mUser?.let {
            if (it.isNobody) {
                return@let
            }
            activity.edit_text.setText(ChatDraftUtils.decodeChatDraft(it.uid))
            loadBackground(activity.background, it)
        }
        GeneralUtil.runFromBackgroundToMain({
            ConversationManager.getInstance().onConversationOpen(chatIntentModel.mChatToken)
            VoiceCallNotificationUtils.instance.clearAllNotification()
            presenter.onStartChat()
        })
    }

    private fun loadBackground(avatar: SimpleDraweeView?, user: User) {
        avatar?.setViewTag(Constant.GlobalViewTagDefine.VIEW_TAG_FOR_USER, user)
        val thumbnailParam = UserImageLoadParam.newBuilder()
                .setUser(user, 56, 56) // same size with the avatar in R.layout.item_main_conversation
                .setPostProcessor(IterativeBoxBlurPostProcessor(2, 4))
                ?.setOverlayResId(R.drawable.chat_background_overlay_shape)
                ?.build()
        val param = UserImageLoadParam.newBuilder()
                .setUser(user, LocalDisplay.SCREEN_WIDTH_DP, LocalDisplay.SCREEN_HEIGHT_DP)
                .setPostProcessor(IterativeBoxBlurPostProcessor(2, 4))
                ?.setOverlayResId(R.drawable.chat_background_overlay_shape)
                ?.setLowResImageLoadParam(thumbnailParam)
                ?.build()
        ImageViewUtil.loadImage(avatar, param)
    }

    override fun updateMessageList(messageList: List<ChatMessageBaseItem>, scrollToBottom: Boolean, isFromSearch: Boolean, messageIndex: Int, messageId: String) {
        dismissSwipeRefresh()
        CLog.d("MessageList", "dispatch to view: ${messageList.size} $scrollToBottom $isFromSearch $messageIndex $messageId")
        var isScrollToBottom: Boolean = scrollToBottom
        if (messageAdapter.itemCount > 0 && activity.message_recyclerview.canScrollVertically(1) && messageList.isNotEmpty() && messageList[0] !is ChatMessageSendBaseItem) {
            isScrollToBottom = false
        }

        if (isFromSearch) {
            if (messageIndex >= 0) {
                var index = 0
                for (i in messageList.indices) {
                    val item = messageList[i]
                    if (item.message.id == messageId) {
                        index = i
                    }
                }
                messageAdapter.update(messageList) {
                    SimpleTask.postDelay({
                        if (index > 0 && index < messageList.size) {
                            activity.message_recyclerview.scrollToPosition(index)
                        }
                    }, 50)
                }
            }
        } else if (isScrollToBottom) {
            CLog.d("MessageList", "scrollToBottom view update ")
            messageAdapter.update(messageList) {
                activity.message_recyclerview.postDelayed({
                    scrollToBottom()
                }, 50)
            }
        } else {
            CLog.d("MessageList", "ordinary view update ")
            messageAdapter.update(messageList)
        }
    }

    override fun updateTitle(title: String?) {
        SimpleTask.post {
            TextViewUtil.displayOrGone(activity.toolbar_title, title)
        }
    }

    override fun updateUnreadCount(count: Int) {
    }

    override fun dismissSwipeRefresh() {
        activity.swipe_refresh_layout.isRefreshing = false
    }

    override fun clearMessageEdit() {
        activity.edit_text.setText("")
        KeyboardUtil.hideKeyboard(activity.edit_text)
    }

    override fun showProgressDialog() {
        if (!activity.isFinishing && !activity.isDestroyed) {
            if (mProgressDialog == null) {
                mProgressDialog = ProgressDialog(activity)
                mProgressDialog?.setMessage("Loading")
                mProgressDialog?.setProgressStyle(ProgressDialog.STYLE_SPINNER)
            }
            mProgressDialog?.show()
        }
    }

    override fun dismissProgressDialog() {
        if (!activity.isFinishing && !activity.isDestroyed) {
            mProgressDialog?.dismiss()
        }
    }

    private fun scrollToBottom() {
        SimpleTask.postDelay({
            if (messageAdapter.itemCount > 1) {
                activity.message_recyclerview.scrollToPosition(messageAdapter.itemCount - 1)
            }
        }, 100)
    }

    private inner class EditTextWatcher : BaseTextWatcher() {
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            activity.send.visibility = if (TextUtils.isEmpty(s)) View.GONE else View.VISIBLE
        }
    }

    override fun hideMediaLayout() {
        KPSwitchConflictUtil.hidePanelAndKeyboard(activity.chat_bottom_emoji_layout)
        changeAudioRecordLifecycle(false)
    }

    override fun updateIntimacy(intimacy: Intimacy) {
        activity.toolbar_title?.visibility = if (intimacy.totalNum >= MIN_TOTAL_NUM) View.GONE else View.VISIBLE
        activity.intimacy_layout?.visibility = if (intimacy.totalNum >= MIN_TOTAL_NUM) View.VISIBLE else View.GONE
        activity.intimacy.text = activity.getString(R.string.chat_toolbar_intimacy, intimacy.totalNum.toString())
        mChatIntentModel?.mUser?.let {
            ImageViewUtil.loadImage(activity.toolbar_left_avatar, UserImageLoadParam.newBuilder().setUser(it, 40, 40).setCornersRadius(8.dp)?.build())
        }
        ImageViewUtil.loadImage(activity.toolbar_right_avatar, UserImageLoadParam.newBuilder().setUser(UserData.getInstance().user, 40, 40).setCornersRadius(8.dp)?.build())
        activity.intimacy_layout.setViewTag(intimacy)
        activity.camera.setViewTag(intimacy)
    }

    override fun enqueueOrPlayGiftAnimation(gift: Gift) {
        if (isGiftAnimationPlaying) {
            mAnimationQueue.offer(gift)
        } else {
            playGiftAnimation(gift)
        }
    }

    override fun performClickCall() {
        activity.call.performClick()
    }

    private fun playGiftAnimation(gift: Gift) {
        isGiftAnimationPlaying = true
        // If I'm an receiver, notice server that this gift has been played
        if (UserData.getInstance().isSelf(gift.toUid)) {
            GiftData.playGiftAnimation(gift.billId)
        }
        if (gift.hasSvga()) {
            RxUtils.disposable(mSvgaAnimationDisposable)
            mSvgaAnimationDisposable = SvgaData.createTaskFromAsset(gift.getSvgaFilename())
                    .compose(RxUtils.ioToMainSingleScheduler())
                    .subscribe({ entity ->

                        activity.svga_animation_view.visibility = View.VISIBLE
                        activity.svga_animation_view.setImageDrawable(SVGADrawable(entity))
                        activity.svga_animation_view.startAnimation()
                    }, { t -> t.printStackTrace() })
        } else {
            mGiftAnimator = ViewAnimator.animate(activity.animation_view)
                    .alpha(0F, 1F)
                    .scale(0F, 1F)
                    .dp().translationY(0F, 200F)
                    .interpolator(AccelerateDecelerateInterpolator())
                    .duration(1500)
                    .onStart {
                        ImageViewUtil.loadImage(activity.animation_view, ImageLoadParam.newBuilder().setUrl(gift.icon).setSizeInDP(72).build())
                        activity.animation_view.visibility = View.VISIBLE
                    }
                    .thenAnimate(activity.animation_view)
                    .alpha(1F, 0F)
                    .scale(1F, 0F)
                    .dp().translationY(200F, 540F)
                    .interpolator(DecelerateInterpolator())
                    .duration(1800)
                    .onStop {
                        activity.animation_view.visibility = View.GONE
                        isGiftAnimationPlaying = false

                        if (mAnimationQueue.isNotEmpty()) {
                            playGiftAnimation(mAnimationQueue.poll())
                        }
                    }
                    .start()
        }
    }

    override fun checkEmoji(key: String) {
        val start: Int = activity.edit_text.selectionStart
        activity.edit_text.text.insert(start, key)
    }

    override fun showTeaseList(list: List<TeaseItem>) {
        teaseAdapter.list = list
        teaseAdapter.notifyDataSetChanged()
    }

    private fun checkPermissionForCamera(successAction: Action) {
        if (activity.isFinishing || activity.isDestroyed) {
            return
        }
        RxPermissions(activity).request(Manifest.permission.CAMERA)
                .subscribe { granted: Boolean ->
                    if (granted) {
                        successAction.run()
                    } else {
                        GlobalUI.getInstance().showToast("请检查您的相机或录音权限是否开启")
                    }
                }.disposeOn(activity)
    }

    private fun checkPermissionForCameraAndAudio(successAction: Action) {
        if (activity.isFinishing || activity.isDestroyed) {
            return
        }
        RxPermissions(activity).request(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
                .subscribe { granted: Boolean ->
                    if (granted) {
                        successAction.run()
                    } else {
                        GlobalUI.getInstance().showToast("请检查您的相机或录音权限是否开启")
                    }
                }.disposeOn(activity)
    }

    private fun initAudioRecord() {
        if (activity.isDestroyed) {
            return
        }
        if (mAudioRecordViewFragment == null) {
            mAudioRecordViewFragment = AudioRecordViewFragment.newInstance()
            mAudioRecordViewFragment?.setRequestTag(presenter.getRequestTag())
            mAudioRecordViewFragment?.let {
                activity.supportFragmentManager
                        .beginTransaction()
                        .replace(R.id.chat_media_audio_record_layout, it)
                        .commitAllowingStateLoss()
            }
        }
    }

    private fun changeAudioRecordLifecycle(isShow: Boolean) {
        mAudioRecordViewFragment?.lifecycleChange(isShow)
    }

    private fun clearGiftAnimation() {
        mAnimationQueue.clear()
        activity.svga_animation_view.visibility = View.GONE
        activity.svga_animation_view.stopAnimation()
        mSvgaAnimationDisposable?.dispose()
        mGiftAnimator?.cancel()
        isGiftAnimationPlaying = false
        activity.animation_view.visibility = View.GONE
    }

    private fun showGiftDialog() {
        hideMediaLayout()
        mChatIntentModel?.mUser?.let {
            ChatGiftBottomSheetDialog.show(activity.supportFragmentManager, it, Constant.From.CHAT)
        }
    }

    private fun checkPermissionForAudio(successAction: Runnable) {
        if (activity.isDestroyed) {
            return
        }
        RxPermissions(activity).request(Manifest.permission.RECORD_AUDIO)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe { granted: Boolean ->
                    if (!granted) {
                        GlobalUI.getInstance().showToast("请检查您的相机或录音权限是否开启")
                    } else {
                        successAction.run()
                    }
                }.disposeOn(activity)
    }
}